package com.guaoran.interview.spring.autowired.service;

import org.springframework.aop.framework.AopContext;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.transaction.interceptor.DefaultTransactionAttribute;
import org.springframework.transaction.interceptor.TransactionAspectSupport;

/**
 * @author : 孤傲然
 * @description :  事务方法调用本地方法 无法代理时，提供两种方式：注入自身和获得当前代理对象
 * @date :2020/1/3 16:23
 */
@Service
@Transactional(propagation = Propagation.REQUIRES_NEW)
public class TransactionService {
    @Autowired
    private TransactionService transactionService;
    @Autowired
    private Transaction2Service transaction2Service;

    public String say() throws Exception{
        System.out.println("111");
        // 方法一 ：注入自身
        transactionService.say2();
        // 方法二 ： 获得当前代理
        // 需要开启对AspectJ自动代理技术： @EnableAspectJAutoProxy(exposeProxy=true)
        TransactionService service = (TransactionService) AopContext.currentProxy();
        service.say3();

        // 测试 在开启事务的时候抛出异常回滚事务，并在该事务中进行捕获，这种可以正常提交，因为这里是两个事务
        try {
            service.say4();
        }catch (Exception e){
            e.printStackTrace();
        }

        // 测试 在当前事务调用另外一个事务方法，（非本类），并在该事务进行捕获
        // 提交时报错 Transaction rolled back because it has been marked as rollback-only
        // 因为使用的时同一个事务， 一个标记位回滚，一个标记为提交。
        try {
            transaction2Service.say3();
        }catch (Exception e){
            e.printStackTrace();
        }
        // 测试事务回滚 ：默认情况下，当throw 非 Error 或 RuntimeException 及子类时，异常会回滚，否则不会回滚
        // 此时 需要在 @Transaction 注解上加上（rollbackFor = Exception.class）
        say5();
        return "say";
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public String say2() {
        System.out.println("222");
        return "2222";
    }
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public String say3() {
        System.out.println("333");
        return "3333";
    }


    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public String say4() {
        System.out.println("444");
        throw new RuntimeException();
    }
    /**
     *  spring 事务回滚 {@link DefaultTransactionAttribute#rollbackOn(java.lang.Throwable)}
     *  当异常是 {@link RuntimeException} 或 {@link Error} 的子类时，
     *  {@link TransactionAspectSupport#completeTransactionAfterThrowing() line:543} 会 rollback ,否则会提交事务
     *
     * @return
     * @throws Exception
     */
    public String say5() throws Exception {
        System.out.println("555");
//        throw new RuntimeException();
//        throw new AbstractMethodError();
        throw new Exception();
    }
}
